﻿/*************************************************************************/
/*                       This file is ported from:                       */
/*                           GODOT ENGINE                                */
/*                    http://www.godotengine.org                         */
/*************************************************************************/

using System.Collections.Generic;
using Godot.core;

namespace Godot.core.os
{
    using SysMethodInfo = System.Reflection.MethodInfo;

    public partial class MainLoop : Object
    {
        protected static void _bind_methods()
        {
            ObjectTypeDB.bind_method("input_event", typeof(MainLoop).GetMethod("input_event"));
            ObjectTypeDB.bind_integer_constant(get_type_static(), "NOTIFICATION_WM_FOCUS_IN", MainLoop.NOTIFICATION_WM_FOCUS_IN);
            ObjectTypeDB.bind_integer_constant(get_type_static(), "NOTIFICATION_WM_FOCUS_OUT", MainLoop.NOTIFICATION_WM_FOCUS_OUT);
            ObjectTypeDB.bind_integer_constant(get_type_static(), "NOTIFICATION_WM_QUIT_REQUEST", MainLoop.NOTIFICATION_WM_QUIT_REQUEST);
            ObjectTypeDB.bind_integer_constant(get_type_static(), "NOTIFICATION_WM_UNFOCUS_REQUEST", MainLoop.NOTIFICATION_WM_UNFOCUS_REQUEST);
        }

        public virtual void input_event(InputEvent p_event)
        {
            if (script_instance != null)
                script_instance.call("input_event", p_event);
        }

        public virtual void input_text(string p_text)
        { 
        }

        public virtual void init()
        {
            if (_init_script != null)
                set_script(_init_script);

            if (script_instance != null)
                script_instance.call("init");
        }

        public virtual bool iteration(float p_time)
        {
            if (script_instance != null)
                return script_instance.call("iteration", p_time);

            return false;
        }

        public virtual bool idle(float p_time)
        {
            if (script_instance != null)
                return script_instance.call("idle",  p_time);

            return false;
        }

        public virtual void finish()
        {
            if (script_instance != null)
            {
                script_instance.call("finish");
                set_script(null); //clear script
            }
        }

        public void set_init_script(Script p_init_script)
        {
            _init_script = p_init_script;
        }

        public MainLoop()
        {
            //Do nothing
        }

        private Script _init_script;
        public const int NOTIFICATION_WM_FOCUS_IN = 5;
        public const int NOTIFICATION_WM_FOCUS_OUT = 6;
        public const int NOTIFICATION_WM_QUIT_REQUEST = 7;
        public const int NOTIFICATION_WM_UNFOCUS_REQUEST = 8; 
    }

    public partial class MainLoop
    {
        #region OBJ_TYPE( MainLoop, Object )
        public override string get_type() { return "MainLoop"; }

        public override string get_save_type() { return get_type(); } //type stored when saving

        public override StringName get_type_name() { return (StringName)get_type_static(); }

        public override bool is_type(string p_type) { return (p_type == "MainLoop") ? true : base.is_type(p_type); }

        protected override void _initialize_typev() { initialize_type(); }

        protected override bool _setv(StringName p_name, Variant p_property)
        {
            if (base._setv(p_name, p_property))
                return true;

            if (typeof(MainLoop).GetMethod("_set") != typeof(Object).GetMethod("_set"))
            {
                return _set(p_name, p_property);
            }

            return false;
        }

        protected override bool _getv(StringName p_name, ref Variant r_property)
        {
            if (typeof(MainLoop).GetMethod("_get") != typeof(Object).GetMethod("_get"))
            {
                if (_get(p_name, ref r_property))
                    return true;
            }

            return base._getv(p_name, ref r_property);
        }

        protected override void _get_property_listv(ref List<PropertyInfo> p_list, bool p_reversed)
        {
            if (!p_reversed)
            {
                base._get_property_listv(ref p_list, p_reversed);
            }

            p_list.Add(new PropertyInfo(Variant.Type.NIL, get_type_static(), PropertyHint.PROPERTY_HINT_NONE, "", (int)PropertyUsageFlags.PROPERTY_USAGE_CATEGORY));

            if (!_is_gpl_reversed())
                ObjectTypeDB.get_property_list("MainLoop", ref p_list, true);

            if (typeof(MainLoop).GetMethod("_get_property_list") != typeof(Object).GetMethod("_get_property_list"))
            {
                _get_property_list(ref p_list);
            }

            if (_is_gpl_reversed())
                ObjectTypeDB.get_property_list("MainLoop", ref p_list, true);

            if (p_reversed)
            {
                base._get_property_listv(ref p_list, p_reversed);
            }
        }

        protected override void _notificationv(int p_notification, bool p_reversed)
        {
            if (!p_reversed)
                base._notificationv(p_notification, p_reversed);

            if (typeof(MainLoop).GetMethod("_notification") != typeof(Object).GetMethod("_notification"))
            {
                _notification(p_notification);
            }

            if (p_reversed)
                base._notificationv(p_notification, p_reversed);
        }

        public static new string get_type_static() { return "MainLoop"; }

        public static new string get_parent_type_static() { return Object.get_type_static(); }

        public static new void get_inheritance_list_static(ref List<string> r_inheritance_list)
        {
            Object.get_inheritance_list_static(ref r_inheritance_list);
            r_inheritance_list.Add(get_type_static());
        }

        public static new string get_category_static()
        {
            string category = Object.get_category_static();
            if (typeof(MainLoop).GetMethod("_get_category") != typeof(Object).GetMethod("_get_category"))
            {
                if (category != "")
                    category += "/";
                category += _get_category();
            }
            return category;
        }

        public static new string inherits_static() { return "Object"; }

        public static new void get_valid_parents_static(ref List<string> p_parents)
        {
            if (typeof(MainLoop).GetMethod("_get_valid_parents_static") != typeof(Object).GetMethod("_get_valid_parents_static"))
            {
                MainLoop._get_valid_parents_static(ref p_parents);
            }

            Object.get_valid_parents_static(ref p_parents);
        }

        public static new void initialize_type()
        {
            if (__initialized)
                return;
            Object.initialize_type();
            ObjectTypeDB._add_type<MainLoop>();

            SysMethodInfo cls_bind = typeof(MainLoop).GetMethod("_bind_methods", Misc.BindingFlags_Greedy);
            SysMethodInfo par_bind = typeof(Object).GetMethod("_bind_methods", Misc.BindingFlags_Greedy);
            if (cls_bind != par_bind)
                cls_bind.Invoke(null, null);
            __initialized = true;
        }

        private static bool __initialized = false;
        #endregion

        #region OBJ_CATEGORY("Main Loop")
        protected static string _get_category()
        {
            return "Main Loop";
        }
        #endregion
    }
}
